home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / libg_261.zip / libg_261 / libg++ / src / Fix.cc < prev    next >
C/C++ Source or Header  |  1994-08-12  |  13KB  |  664 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3. Copyright (C) 1989 Free Software Foundation
  4.     written by Doug Lea (dl@rocky.oswego.edu)
  5.  
  6. This file is part of the GNU C++ Library.  This library is free
  7. software; you can redistribute it and/or modify it under the terms of
  8. the GNU Library General Public License as published by the Free
  9. Software Foundation; either version 2 of the License, or (at your
  10. option) any later version.  This library is distributed in the hope
  11. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  12. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  13. PURPOSE.  See the GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. //
  19. // Fix.cc : variable length fixed point data type class functions
  20. //
  21.  
  22. #ifdef __GNUG__
  23. #pragma implementation
  24. #endif
  25. #include <Fix.h>
  26. #include <std.h>
  27. #include <Obstack.h>
  28. #include <AllocRing.h>
  29. #include <strstream.h>
  30.  
  31. // member constants
  32.  
  33. const _G_uint16_t Fix::min_length;
  34. const _G_uint16_t Fix::max_length;
  35. const double Fix::min_value;
  36. const double Fix::max_value;
  37.  
  38. // default parameters
  39.  
  40. _G_uint16_t Fix::default_length = 16;
  41. int    Fix::default_print_width = 8;
  42.  
  43. Fix::PEH Fix::overflow_handler = Fix::overflow_saturate;
  44.  
  45. Fix::Rep Fix::Rep_0    = { 16, 1, 1, { 0 } };
  46. Fix::Rep Fix::Rep_m1    = { 16, 1, 1, { 0x8000 } };
  47. Fix::Rep Fix::Rep_quotient_bump = { 16, 1, 1, { 0x4000 } };
  48.  
  49. // error handling
  50.  
  51. void
  52. Fix::default_error_handler(const char* msg)
  53. {
  54.   cerr << "Fix: " << msg << "\n";
  55.   abort();
  56. }
  57.  
  58. void
  59. Fix::default_range_error_handler(const char* msg)
  60. {
  61.   cerr << "Fix: range error in " << msg << "\n";
  62.   //abort();
  63. }
  64.  
  65. one_arg_error_handler_t 
  66.   Fix::error_handler = Fix::default_error_handler,
  67.   Fix::range_error_handler = Fix::default_range_error_handler;
  68.  
  69. one_arg_error_handler_t
  70. Fix::set_error_handler(one_arg_error_handler_t f)
  71. {
  72.   one_arg_error_handler_t old = error_handler;
  73.   error_handler = f;
  74.   return old;
  75. }
  76.  
  77. one_arg_error_handler_t
  78. Fix::set_range_error_handler(one_arg_error_handler_t f)
  79. {
  80.   one_arg_error_handler_t old = range_error_handler;
  81.   range_error_handler = f;
  82.   return old;
  83. }
  84.  
  85. void
  86. Fix::error(const char* msg)
  87. {
  88.   error_handler(msg);
  89. }
  90.  
  91. void
  92. Fix::range_error(const char* msg)
  93. {
  94.   range_error_handler(msg);
  95. }
  96.  
  97. // Fix::Rep allocation and initialization functions
  98.  
  99. static inline Fix::Rep*
  100. _new_Fix(_G_uint16_t len)
  101. {
  102.   int siz = (((_G_uint32_t) len + 15) >> 4);
  103.   if (siz <= 0) siz = 1;
  104.   unsigned int allocsiz = (sizeof(Fix::Rep) + (siz - 1) * sizeof(_G_uint16_t));
  105.   Fix::Rep* z = (Fix::Rep*)(new char[allocsiz]);
  106.   memset(z, 0, allocsiz);
  107.   z->len = len;
  108.   z->siz = siz;
  109.   z->ref = 1;
  110.   return z;
  111. }
  112.  
  113. Fix::Rep*
  114. Fix::new_Fix(_G_uint16_t len)
  115. {
  116.   return _new_Fix(len);
  117. }
  118.  
  119. Fix::Rep*
  120. Fix::new_Fix(_G_uint16_t len, const Rep* x)
  121. {
  122.   Rep* z = _new_Fix(len);
  123.   return copy(x,z);
  124. }
  125.  
  126. Fix::Rep*
  127. Fix::new_Fix(_G_uint16_t len, double d)
  128. {
  129.   Rep* z = _new_Fix(len);
  130.  
  131.   if ( d == max_value )
  132.   {
  133.     z->s[0] = 0x7fff;
  134.     for ( int i=1; i < z->siz; i++ )
  135.       z->s[i] = 0xffff;
  136.   }
  137.   else if ( d < min_value || d > max_value )
  138.     range_error("declaration");
  139.   else
  140.   {
  141.     if (d < 0)
  142.       d += 2.0;
  143.     d *= 32768;
  144.     for ( int i=0; i < z->siz; i++ )
  145.     {
  146.       z->s[i] = (_G_uint16_t )d;
  147.       d -= z->s[i];
  148.       d *= 65536;
  149.     }
  150.     if ( d >= 32768 )
  151.       z->s[z->siz-1]++;
  152.   }
  153.   mask(z);
  154.   return z;
  155. }
  156.  
  157. // convert to a double 
  158.  
  159. double
  160. value(const Fix& x)
  161.   double d = 0.0;
  162.   for ( int i=x.rep->siz-1; i >= 0; i-- )
  163.   {
  164.     d += x.rep->s[i];
  165.     d *= 1./65536.;
  166.   }
  167.   d *= 2.;
  168.   return d < 1. ? d : d - 2.;
  169. }
  170.  
  171. // extract mantissa to Integer
  172.  
  173. Integer
  174. mantissa(const Fix& x)
  175. {
  176.   Integer a = 1, b=1;
  177.   for ( int i=0; i < x.rep->siz; i++ )
  178.   {
  179.     a <<= 16;
  180.     a += x.rep->s[i];
  181.     b <<= 16;
  182.   }
  183.   return a-b;
  184. }
  185.  
  186. // comparison functions
  187.   
  188. inline static int
  189. docmp(const _G_uint16_t* x, const _G_uint16_t* y, int siz)
  190. {
  191.   int diff = (_G_int16_t )*x - (_G_int16_t )*y;
  192.   while ( --siz && !diff )
  193.     diff = (_G_int32_t )(_G_uint32_t )*++x - (_G_int32_t )(_G_uint32_t )*++y;
  194.   return diff;
  195. }
  196.  
  197. inline static int
  198. docmpz(const _G_uint16_t* x, int siz)
  199. {
  200.   while ( siz-- )
  201.     if ( *x++ ) return 1;
  202.   return 0;
  203. }
  204.  
  205. int
  206. Fix::compare(const Rep* x, const Rep* y)
  207. {
  208.   if ( x->siz == y->siz )
  209.     return docmp(x->s, y->s, x->siz);
  210.   else
  211.   {
  212.     int r;
  213.     const Rep* longer, *shorter;
  214.     if ( x->siz > y->siz )
  215.     {
  216.       longer = x;
  217.       shorter = y;
  218.       r = 1;
  219.     }
  220.     else
  221.     {
  222.       longer = y;
  223.       shorter = x;
  224.       r = -1;
  225.     }
  226.     int diff = docmp(x->s, y->s, shorter->siz);
  227.     if ( diff )
  228.       return diff;
  229.     else if ( docmpz(&longer->s[shorter->siz], longer->siz-shorter->siz) )
  230.       return r;
  231.     else
  232.       return 0;
  233.   }
  234. }
  235.  
  236. // arithmetic functions
  237.  
  238. Fix::Rep*
  239. Fix::add(const Rep* x, const Rep* y, Rep* r)
  240. {
  241.   _G_uint16_t xsign = x->s[0], ysign = y->s[0];
  242.   const Rep* longer, *shorter;
  243.   if ( x->len >= y->len )
  244.     longer = x, shorter = y;
  245.   else
  246.     longer = y, shorter = x;
  247.   if ( r == NULL )
  248.     r = new_Fix(longer->len);
  249.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  250.     r->s[i] = 0;
  251.   for ( ; i >= shorter->siz; i-- )
  252.     r->s[i] = longer->s[i];
  253.   _G_uint32_t sum = 0, carry = 0;
  254.   for ( ; i >= 0; i-- )
  255.   {
  256.     sum = carry + (_G_uint32_t )x->s[i] + (_G_uint32_t )y->s[i];
  257.     carry = sum >> 16;
  258.     r->s[i] = sum;
  259.   }
  260.   if ( (xsign ^ sum) & (ysign ^ sum) & 0x8000 )
  261.     overflow_handler(r);
  262.   return r;
  263. }
  264.  
  265. Fix::Rep*
  266. Fix::subtract(const Rep* x, const Rep* y, Rep* r)
  267. {
  268.   _G_uint16_t xsign = x->s[0], ysign = y->s[0];
  269.   const Rep* longer, *shorter;
  270.   if ( x->len >= y->len )
  271.     longer = x, shorter = y;
  272.   else
  273.     longer = y, shorter = x;
  274.   if ( r == NULL )
  275.     r = new_Fix(longer->len);
  276.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  277.     r->s[i] = 0;
  278.   for ( ; i >= shorter->siz; i-- )
  279.     r->s[i] = (longer == x ? x->s[i] : -y->s[i]);
  280.   _G_int16_t carry = 0;
  281.   _G_uint32_t sum = 0;
  282.   for ( ; i >= 0; i-- )
  283.   {
  284.     sum = (_G_int32_t )carry + (_G_uint32_t )x->s[i] - (_G_uint32_t )y->s[i];
  285.     carry = sum >> 16;
  286.     r->s[i] = sum;
  287.   }
  288.   if ( (xsign ^ sum) & (~ysign ^ sum) & 0x8000 )
  289.     overflow_handler(r);
  290.   return r;
  291. }
  292.  
  293. Fix::Rep*
  294. Fix::multiply(const Rep* x, const Rep* y, Rep* r)
  295. {
  296.   if ( r == NULL )
  297.     r = new_Fix(x->len + y->len);
  298.   int xsign = x->s[0] & 0x8000,
  299.     ysign = y->s[0] & 0x8000;
  300.   Fix X(x->len), Y(y->len);
  301.   if ( xsign )
  302.     x = negate(x,X.rep);
  303.   if ( ysign )
  304.     y = negate(y,Y.rep);
  305.   for ( int i=0; i < r->siz; i++ )
  306.     r->s[i] = 0;
  307.   for ( i=x->siz-1; i >= 0; i-- )
  308.   {
  309.     _G_uint32_t carry = 0;
  310.     for ( int j=y->siz-1; j >= 0; j-- ) 
  311.     {
  312.       int k = i + j + 1;
  313.       _G_uint32_t a = (_G_uint32_t )x->s[i] * (_G_uint32_t )y->s[j];
  314.       _G_uint32_t b = ((a << 1) & 0xffff) + carry;
  315.       if ( k < r->siz )
  316.       {
  317.     b += r->s[k];
  318.         r->s[k] = b;
  319.       }
  320.       if ( k < (int)r->siz + 1 )
  321.         carry = (a >> 15) + (b >> 16);
  322.     }
  323.     r->s[i] = carry;
  324.   }
  325.   if ( xsign != ysign )
  326.     negate(r,r);
  327.   return r;
  328. }
  329.  
  330. Fix::Rep*
  331. Fix::multiply(const Rep* x, int y, Rep* r)
  332. {
  333.   if ( y != (_G_int16_t )y )
  334.     range_error("multiply by int -- int too large");
  335.   if ( r == NULL )
  336.     r = new_Fix(x->len);
  337.   for ( int i=r->siz-1; i >= x->siz; i-- )
  338.     r->s[i] = 0;
  339.   _G_int32_t a, carry = 0;
  340.   for ( ; i > 0; i-- )
  341.   {
  342.     a = (_G_int32_t) (_G_uint32_t )x->s[i] * y + carry;
  343.     r->s[i] = a;
  344.     carry = a >> 16;        // assumes arithmetic right shift
  345.   }
  346.   a = (_G_int32_t) (_G_int16_t )x->s[0] * y + carry;
  347.   r->s[0] = a;
  348.   a &= 0xffff8000L;
  349.   if ( a != (_G_int32_t)0xffff8000L && a != (_G_int32_t)0L ) {
  350.     r->s[0] = 0x8000 ^ x->s[0] ^ y;
  351.     overflow_handler(r);
  352.   }
  353.   return r;
  354. }
  355.  
  356. Fix::Rep*
  357. Fix::divide(const Rep* x, const Rep* y, Rep* q, Rep* r)
  358. {
  359.   int xsign = x->s[0] & 0x8000, 
  360.     ysign = y->s[0] & 0x8000;
  361.   if ( q == NULL )
  362.     q = new_Fix(x->len);
  363.   copy(&Rep_0,q);
  364.   if ( r == NULL )
  365.     r = new_Fix(x->len + y->len - 1);
  366.   if ( xsign )
  367.     negate(x,r);
  368.   else
  369.     copy(x,r);
  370.   Fix Y(y->len);
  371.   Rep* y2 = ( ysign ? negate(y,Y.rep) : copy(y,Y.rep) );
  372.   if ( !compare(y2) )
  373.     range_error("division -- division by zero");
  374.   else if ( compare(x,y2) >= 0 )
  375.     if ( compare(x,y2) == 0 && (xsign ^ ysign) != 0 )
  376.     {
  377.       copy(&Rep_m1,q);
  378.       copy(&Rep_0,r);
  379.     }
  380.     else
  381.       range_error("division");
  382.   else
  383.   {
  384.     Rep* t;
  385.     Fix S(r->len),
  386.       W(q->len,&Rep_quotient_bump);
  387.     for ( int i=1; i < q->len; i++ )
  388.     {
  389.       shift(y2,-1,y2);
  390.       subtract(r,y2,S.rep);
  391.       int s_status = compare(S.rep);
  392.       if ( s_status == 0 ) 
  393.       {
  394.     t = r, r = S.rep, S.rep = t;
  395.     break;
  396.       }
  397.       else if ( s_status > 0 )
  398.       {
  399.     t = r, r = S.rep, S.rep = t;
  400.     add(q,W.rep,q);
  401.       }
  402.       shift(W.rep,-1,W.rep);
  403.     }
  404.     if ( xsign ^ ysign )
  405.       negate(q,q);
  406.   }
  407.   return q;
  408. }
  409.  
  410. Fix::Rep*
  411. Fix::shift(const Rep* x, int y, Rep* r)
  412. {
  413.   if ( r == NULL )
  414.     r = new_Fix(x->len);
  415.   if ( y == 0 )
  416.     {
  417.       copy (x, r);
  418.       return r;
  419.     }
  420.  
  421.   int ay = abs((_G_int32_t) y),
  422.     ayh = ay >> 4,
  423.     ayl = ay & 0x0f;
  424.   int xl, u, ilow, ihigh;
  425.   _G_uint16_t *rs;
  426.   const _G_uint16_t *xsl, *xsr;
  427.  
  428.   if ( y > 0 )
  429.   {
  430.     rs = r->s;
  431.     xsl = x->s + ayh;
  432.     xsr = xsl + 1;
  433.     xl = ayl;
  434.     u = 1;
  435.     ihigh = x->siz - ayh - 1;
  436.     ilow = 0;
  437.   }
  438.   else
  439.   {
  440.     rs = &r->s[r->siz - 1];
  441.     xsr = &x->s[r->siz - 1] - ayh;
  442.     xsl = xsr - 1;
  443.     xl = 16 - ayl;
  444.     u = -1;
  445.     ihigh = r->siz - ayh - 1;
  446.     ilow = ihigh - x->siz;
  447.   }
  448.  
  449.   int xr = 16 - xl;
  450.   _G_uint16_t xrmask = 0xffffL >> xr;
  451.   for ( int i=0; i < ilow; i++, rs+=u, xsl+=u, xsr+=u )
  452.     *rs = 0;
  453.   for ( ; i < ihigh; i++, rs+=u, xsl+=u, xsr+=u )
  454.     *rs = (*xsl << xl) + ((*xsr >> xr) & xrmask);
  455.   *rs = (y > 0 ? (*xsl << xl) : ((*xsr >> xr) & xrmask));
  456.   rs += u;
  457.   for ( ; ++i < r->siz; rs+=u )
  458.     *rs = 0;
  459.   return r;
  460. }
  461.  
  462. Fix::Rep*
  463. Fix::negate(const Rep* x, Rep* r)
  464. {
  465.   if ( r == NULL )
  466.     r = new_Fix(x->len);
  467.   _G_uint32_t carry = 1;
  468.   for ( int i=r->siz-1; i >= x->siz; i-- )
  469.     r->s[i] = 0;
  470.   for ( ; i >= 0; i-- )
  471.   {
  472.     _G_uint32_t a = (_G_uint16_t )~x->s[i] + carry;    // bug work-around
  473.     r->s[i] = a;
  474.     carry = a >> 16;
  475.   }
  476.   return r;
  477. }
  478.  
  479. // io functions
  480.  
  481. Fix
  482. atoF(const char* a, int len)
  483. {
  484.   return Fix(len,atof(a));
  485. }
  486.  
  487. extern AllocRing _libgxx_fmtq;
  488.  
  489. void
  490. Fix::printon(ostream& s, int width) const
  491. {
  492.   double val = value(*this);
  493.   int old_precision = s.precision(width-3);
  494.   _G_int32_t old_flags = s.setf(ios::fixed, ios::fixed|ios::scientific);
  495.   if (val >= 0)
  496.       s << ' ';
  497.   s.width(width-2);
  498.   s << val;
  499.   s.precision(old_precision);
  500.   s.flags(old_flags);
  501. }
  502.  
  503. char*
  504. Ftoa(Fix& x, int width)
  505. {
  506.   int wrksiz = width + 2;
  507.   char *fmtbase = (char *) _libgxx_fmtq.alloc(wrksiz);
  508.   ostrstream stream(fmtbase, wrksiz);
  509.   
  510.   x.printon(stream, width);
  511.   stream << ends;
  512.   return fmtbase;
  513. }
  514.  
  515. extern Obstack _libgxx_io_ob;
  516.  
  517. Fix
  518. Fix::operator %= (int y)
  519. {
  520.   Fix r((int )rep->len + y, *this); return *this = r;
  521. }
  522.  
  523. istream&
  524. operator >> (istream& s, Fix& y)
  525. {
  526.   int got_one = 0;
  527.   if (!s.ipfx(0))
  528.   {
  529.     s.clear(ios::failbit|s.rdstate()); // Redundant if using GNU iostreams.
  530.     return s;
  531.   }
  532.  
  533.   char sign = 0, point = 0;
  534.   char ch;
  535.   s >> ws;
  536.   if (!s.good())
  537.   {
  538.     s.clear(ios::failbit|s.rdstate());
  539.     return s;
  540.   }
  541.   while (s.get(ch))
  542.   {
  543.     if (ch == '-')
  544.     {
  545.       if (sign == 0)
  546.       {
  547.         sign = 1;
  548.         _libgxx_io_ob.grow(ch);
  549.       }
  550.       else
  551.         break;
  552.     }
  553.     if (ch == '.')
  554.     {
  555.       if (point == 0)
  556.       {
  557.         point = 1;
  558.         _libgxx_io_ob.grow(ch);
  559.       }
  560.       else
  561.         break;
  562.     }
  563.     else if (ch >= '0' && ch <= '9')
  564.     {
  565.       got_one = 1;
  566.       _libgxx_io_ob.grow(ch);
  567.     }
  568.     else
  569.       break;
  570.   }
  571.   char * p = (char*)(_libgxx_io_ob.finish(0));
  572.   if (s.good())
  573.     s.putback(ch);
  574.   if (!got_one)
  575.     s.clear(ios::failbit|s.rdstate());
  576.   else
  577.     y = atoF(p);
  578.   _libgxx_io_ob.free(p);
  579.   return s;
  580. }
  581.  
  582. void
  583. show(const Fix& x)
  584. {
  585.   cout << "len = " << x.rep->len << "\n";
  586.   cout << "siz = " << x.rep->siz << "\n";
  587.   cout << "ref = " << x.rep->ref << "\n";
  588.   cout << "man = ";
  589. #ifdef _OLD_STREAMS
  590.   cout << Itoa(mantissa(x),16,4*x.rep->siz);
  591. #else
  592.   int old_flags = cout.setf(ios::hex, ios::hex|ios::dec|ios::oct);
  593.   cout.width(4*x.rep->siz);
  594.   cout << mantissa(x);
  595.   cout.setf(old_flags, ios::hex|ios::dec|ios::oct);
  596. #endif
  597.   cout << "\n";
  598.   cout << "val = " << value(x) << "\n";
  599. }
  600.  
  601. // parameter setting operations
  602.  
  603. Fix::PEH Fix::set_overflow_handler(PEH new_handler)
  604. {
  605.   PEH old_handler = overflow_handler;
  606.   overflow_handler = new_handler;
  607.   return old_handler;
  608. }
  609.  
  610. int
  611. Fix::set_default_length(int newlen)
  612. {
  613.   _G_uint16_t oldlen = default_length;
  614.   if ( newlen < min_length || newlen > max_length )
  615.     error("illegal length in Fix::set_default_length");
  616.   default_length = newlen;
  617.   return oldlen;
  618. }
  619.  
  620. // overflow handlers
  621.  
  622. void
  623. Fix::overflow_saturate(Rep* r)
  624. {
  625.   if ( (_G_int16_t) r->s[0] > 0 ) 
  626.   {
  627.     r->s[0] = 0x8000;
  628.     for ( int i=1; i < r->siz; i++ )
  629.       r->s[i] = 0;
  630.   }
  631.   else
  632.   {
  633.     r->s[0] = 0x7fff;
  634.     for ( int i = 1; i < (int)r->siz; i++ )
  635.       r->s[i] = 0xffff;
  636.     mask(r);
  637.   }
  638. }
  639.  
  640. void
  641. Fix::overflow_wrap(Rep*)
  642. {}
  643.  
  644. void
  645. Fix::overflow_warning_saturate(Rep* r)
  646. {
  647.   overflow_warning(r);
  648.   overflow_saturate(r);
  649. }
  650.  
  651. void
  652. Fix::overflow_warning(Rep*)
  653. {
  654.   cerr << "Fix: overflow warning\n"; 
  655. }
  656.  
  657. void
  658. Fix::overflow_error(Rep*)
  659. {
  660.   cerr << "Fix: overflow error\n"; 
  661.   abort();
  662. }
  663.